package com.janetfilter.core.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;

/**
 * 进程工具类
 * 提供获取当前进程ID以及启动和管理外部进程的功能
 * 同时包含输出重定向的工具方法
 */
public class ProcessUtils {
    // 当前进程ID的缓存，避免重复获取
    private static String processId;

    /**
     * 获取当前Java进程的ID
     * 通过ManagementFactory.getRuntimeMXBean().getName()获取，格式通常为"进程ID@主机名"
     * 
     * @return 当前进程ID字符串
     */
    public synchronized static String currentId() {
        if (null == processId) {
            String name = ManagementFactory.getRuntimeMXBean().getName() + "@";
            // 分割字符串，获取@前面的进程ID部分
            processId = name.split("@", 2)[0];
        }

        return processId;
    }

    /**
     * 启动外部进程，将标准输出和错误输出重定向到系统的标准输出和错误输出
     * 
     * @param pb 进程构建器
     * @return 进程的退出值
     * @throws Exception 如果启动进程或重定向输出失败
     */
    public static int start(ProcessBuilder pb) throws Exception {
        return start(pb, System.out, System.err);
    }

    /**
     * 启动外部进程，将标准输出重定向到指定的输出流，错误输出忽略
     * 
     * @param pb 进程构建器
     * @param out 标准输出重定向目标
     * @return 进程的退出值
     * @throws Exception 如果启动进程或重定向输出失败
     */
    public static int start(ProcessBuilder pb, OutputStream out) throws Exception {
        return start(pb, out, null);
    }

    /**
     * 启动外部进程，将标准输出和错误输出重定向到指定的输出流
     * 
     * @param pb 进程构建器
     * @param out 标准输出重定向目标，如果为null则忽略
     * @param err 错误输出重定向目标，如果为null则忽略
     * @return 进程的退出值
     * @throws Exception 如果启动进程或重定向输出失败
     */
    public static int start(ProcessBuilder pb, OutputStream out, OutputStream err) throws Exception {
        // 启动进程
        Process p = pb.start();

        // 创建重定向线程
        List<Thread> threads = new ArrayList<>();
        if (null != out) {
            threads.add(new Thread(new RedirectOutput(p.getInputStream(), out)));
        }
        if (null != err) {
            threads.add(new Thread(new RedirectOutput(p.getErrorStream(), err)));
        }

        // 启动所有重定向线程
        for (Thread thread : threads) {
            thread.start();
        }
        // 等待所有重定向线程完成
        for (Thread thread : threads) {
            thread.join();
        }

        // 等待进程完成并返回退出值
        return p.waitFor();
    }

    /**
     * 重定向输出的线程任务
     * 从输入流读取数据并写入到输出流
     */
    static class RedirectOutput implements Runnable {
        // 缓冲区大小
        private static final int BUFF_SIZE = 1024;
        // 源输入流
        private final InputStream origin;
        // 目标输出流
        private final OutputStream dest;

        /**
         * 创建重定向输出任务
         * 
         * @param origin 源输入流
         * @param dest 目标输出流
         */
        RedirectOutput(InputStream origin, OutputStream dest) {
            this.origin = origin;
            this.dest = dest;
        }

        /**
         * 执行重定向任务
         * 从源输入流读取数据并写入到目标输出流
         */
        public void run() {
            int length;
            byte[] buffer = new byte[BUFF_SIZE];

            try {
                // 读取数据直到流结束
                while ((length = origin.read(buffer)) != -1) {
                    dest.write(buffer, 0, length);
                }
            } catch (IOException e) {
                throw new RuntimeException("ERROR: Redirect output failed.", e);
            }
        }
    }
}
